package com.gzyz.cheetah.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gzyz.cheetah.entity.dto.PageDTO;
import com.gzyz.cheetah.entity.pagerequest.UserPageRequestRequest;
import com.gzyz.cheetah.entity.table.User;
import com.gzyz.cheetah.enums.entityproperty.UserStatus;
import com.gzyz.cheetah.exception.RegisterException;
import com.gzyz.cheetah.exception.UserServiceException;
import com.gzyz.cheetah.mapper.UserMapper;
import com.gzyz.cheetah.service.IUserService;
import com.gzyz.cheetah.util.RedisUtil;
import com.gzyz.cheetah.util.TokenUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.gzyz.cheetah.util.SecurePass.securePass;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author xclhove
 * @since 2023-11-06
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

   @Value("${cheetah.user.default-password}")
   private String userDefaultPassword;
   private final RedisUtil redis;
   
    /**
     * @author young
     */

    @Autowired
    private  RedisUtil redisUtil;

    @Override
    public String login(String username, String password) {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<User>()
                    .eq(User::getUsername,username);
        User user = this.getOne(userLambdaQueryWrapper);
        if (user == null){
            throw new UserServiceException("账号不存在！");
        }
        String securePass = securePass(password,username);
        if (!securePass.equals(user.getPassword())) {
            throw new UserServiceException("账号或密码错误");
        }
        if(user.getStatus() == UserStatus.FROZEN){
            throw new UserServiceException("当前用户处于禁用状态，请联系管理员");
        }
        //获取redis中的token
        String userTokenKey = "user_token";
        String userTokenInRedis = redis.getHashString(userTokenKey, user.getId());
        boolean validatePass = TokenUtil.validate(userTokenInRedis, securePass);
        if (validatePass) { //验证redis中的token
            return userTokenInRedis;
        }
        //生成token
        String token = TokenUtil.generate(user.getId(), securePass);
        redis.setHashString(userTokenKey, user.getId(), token);
        return token;
    }

    /**
     * @author young
     */
    @Override
    public boolean register(User user) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getUsername,user.getUsername());
        if (this.getOne(lambdaQueryWrapper)!= null){
            throw new RegisterException("该用户已存在，请更换用户名！");
        }else {
            String securePass = securePass(user.getPassword(), user.getUsername());
            user.setPassword(securePass);
            return this.save(user);
        }
    }

    /**
     * @author young
     */
    @Override
    public boolean logout(Integer userId) {
        String userTokenKey = "user_token";
        redisUtil.deleteHashString(userTokenKey, String.valueOf(userId));
        return true;
    }
    
    @Override
    public boolean freezeUserById(Integer userId) {
        User user = this.getById(userId);
        user.setStatus(UserStatus.FROZEN);
        user.setUpdateTime(LocalDateTime.now());
        return this.updateById(user);
    }
    
    @Override
    public boolean unFreezeUserById(Integer userId) {
        User user = this.getById(userId);
        user.setStatus(UserStatus.NORMAL);
        user.setUpdateTime(LocalDateTime.now());
        return this.updateById(user);
    }

    @Transactional
    @Override
    public boolean freezeUsersByIds(List<Integer> userIds) {
        List<User> users = new ArrayList<>();
        for (Integer userId:userIds) {
            User user = this.getById(userId);
            user.setUpdateTime(LocalDateTime.now());
            user.setStatus(UserStatus.FROZEN);
            users.add(user);
        }
        return this.updateBatchById(users);
    }

    @Transactional
    @Override
    public boolean unFreezeUsersByIds(List<Integer> userIds) {
        List<User> users = new ArrayList<>();
        for (Integer userId:userIds) {
            User user = this.getById(userId);
            user.setUpdateTime(LocalDateTime.now());
            user.setStatus(UserStatus.NORMAL);
            users.add(user);
        }
        return this.updateBatchById(users);
    }

    /**
     * @author young
     */
    @Override
    public boolean resetpassword(Integer id) {
        User user = this.getById(id);
        String securePass = securePass(userDefaultPassword, user.getUsername());
        user.setPassword(securePass);
        user.setUpdateTime(LocalDateTime.now());
        return this.updateById(user);
    }

    /**
     * @author young
     */
    @Override
    public boolean delete(Integer id) {
        return this.removeById(id);
    }

    /**
     * @author young
     */

    @Override
    public PageDTO<User> pageListAndSearch(UserPageRequestRequest userPageRequest) {
        Page<User> page = new Page<>(userPageRequest.getPageNo(),userPageRequest.getPageSize());
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper
                .like(!StrUtil.isBlank(userPageRequest.getUsername()),User::getUsername,userPageRequest.getUsername());
        if (!StrUtil.isBlank(userPageRequest.getUsername()) && !StrUtil.isBlank(userPageRequest.getPhone())) {
            userLambdaQueryWrapper.and(i -> i.like(!StrUtil.isBlank(userPageRequest.getPhone()), User::getPhone, userPageRequest.getPhone()));
        }else {
            userLambdaQueryWrapper.like(!StrUtil.isBlank(userPageRequest.getPhone()), User::getPhone, userPageRequest.getPhone());
        }
        if (!StrUtil.isBlank(userPageRequest.getEmail())) {
            userLambdaQueryWrapper.and(i -> i.like(!StrUtil.isBlank(userPageRequest.getEmail()),User::getEmail,userPageRequest.getEmail()));
        }else {
            userLambdaQueryWrapper.like(!StrUtil.isBlank(userPageRequest.getEmail()), User::getEmail, userPageRequest.getEmail());
        }
        userLambdaQueryWrapper.orderBy(true,false,User::getUpdateTime);
        List<User> records = this.page(page,userLambdaQueryWrapper).getRecords();
        int total = this.list(userLambdaQueryWrapper).size();
        PageDTO<User> pageDTO = new PageDTO<>();
        pageDTO.setDataLists(records);
        pageDTO.setTotal(total);
        return pageDTO;
    }


    /**
     * @author young
     */
    @Override
    public boolean changepassword(Integer id,String password) {
        User user = this.getById(id);
        user.setUpdateTime(LocalDateTime.now());
        user.setPassword(securePass(password,user.getUsername()));
        return this.updateById(user);
    }

    @Override
    public boolean update(User user) {
        return this.updateById(user);
    }

    @Transactional
    @Override
    public boolean deleteByIds(List<Integer> userIds) {
        return this.removeByIds(userIds);
    }

    @Override
    public User searchUser(int id) {
        return this.getById(id);
    }

    @Override
    public boolean verifyAndChangePass(String code, String password,String email) {
        String verifyCode = redisUtil.getString(code);
        if (verifyCode.equals(code)){
            LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
            userLambdaQueryWrapper.eq(User::getEmail,email);
            User user = this.getOne(userLambdaQueryWrapper);
            String username = user.getUsername();
            user.setPassword(securePass(password,username));
          return this.updateById(user);
        }else {
            return false;
        }
    }

    @Override
    public String getCode(String username,String email) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getEmail,email)
                .eq(User::getUsername,username);
        User user = this.getOne(queryWrapper);
        if (user == null){
            throw new UserServiceException("查询不到该用户！请检查邮箱输入是否正确！");
        }else {
            String code = SecureUtil.md5(email).substring(0,6);
            redisUtil.setString(code,code,1, TimeUnit.MINUTES);
            return code;
        }
    }
    
    @Override
    public boolean changeStorageSize(User user) {
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getId, user.getId())
                .set(User::getStorageSize, user.getStorageSize());
        boolean updateSuccess = this.update(updateWrapper);
        if (!updateSuccess) {
            throw new UserServiceException("修改失败！");
        }
        return true;
    }
}
